﻿using MicroDal;
using MicroDal.Providers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;

namespace MicroDalTests
{
	[TestClass]
	public class DataSessionTest
	{
		[TestMethod]
		public void DbResourceCall_ReportParameterValues()
		{
			object expected = "Abc123", actual = null;

			using (var sut = new DataSession("TestDb"))
			{
				sut.DbResourceCall += (s, ea) =>
				{
					actual = ea.Parameters[0];
				};

				sut.Execute("SELECT * FROM test WHERE id = @a", expected);
			}

			Assert.AreEqual(expected, actual);
		}

		[TestMethod]
		public void DbResourceCall_Fetch_ShouldBeHitBeforeCallingMoveNext()
		{
			bool called = false;
			using (var sut = new DataSession("TestDb"))
			{
				sut.DbResourceCall += (s, ea) =>
				{
					called = true;
				};

				// We have defered execution here:
				var enumerator = sut.Fetch<object>("SELECT * FROM test");
				Assert.IsNotNull(enumerator);
			}
			// We exited without ever calling 'MoveNext'

			Assert.IsTrue(called);
		}

		[TestMethod]
		public void Fetch_Select_Enumerator()
		{
			using (var sut = new DataSession("TestDb"))
			{
				var enumerator = sut.Fetch("SELECT * FROM test");
				Assert.IsNotNull(enumerator);
			}
		}

        [TestMethod] // TODO: Write better decoupled test
        public void SetMapper()
        {
			using (var sut = new DataSession("TestDb"))
			{
                var str = "Hello there";
                sut.SetMapper(r => r.GetString(0));
                var result = DataSession._mapCache.Get<string>()(new TestDbReader("col1", str));

                Assert.AreEqual(str, result);
            }
           
        }

        [TestMethod, ExpectedException(typeof(InvalidOperationException))]
        public void GetTransaction_ActiveTransaction_Throws()
        {
            using (var sut = new DataSession("TestDb"))
            {
                var tx = sut.GetTransaction();
                var tx2 = sut.GetTransaction();
            }
        }
        
        [TestMethod]
        public void GetTransaction_ClosedTransaction_Possible()
        {
            using (var sut = new DataSession("TestDb"))
            {
                var tx = sut.GetTransaction();
                tx.Rollback();
                var tx2 = sut.GetTransaction();
            }
        }

        [TestMethod]
        public void HasOpenTransaction_ActiveTransaction_True()
        {
            using (var sut = new DataSession("TestDb"))
            {
                var tx = sut.GetTransaction();

                Assert.IsTrue(sut.HasOpenTransaction);
            }
        }

        [TestMethod]
        public void HasOpenTransaction_NoActiveTransaction_False()
        {
            using (var sut = new DataSession("TestDb"))
            {
                Assert.IsFalse(sut.HasOpenTransaction);
            }
        }

        [TestMethod]
        public void HasOpenTransaction_CommittetActiveTransaction_False()
        {
            using (var sut = new DataSession("TestDb"))
            {
                var tx = sut.GetTransaction();
                tx.Commit();
                Assert.IsFalse(sut.HasOpenTransaction);
            }
        }

        [TestMethod]
        public void HasOpenTransaction_RolledbackActiveTransaction_False()
        {
            using (var sut = new DataSession("TestDb"))
            {
                var tx = sut.GetTransaction();
                tx.Dispose();
                Assert.IsFalse(sut.HasOpenTransaction);
            }
        }
		
	}
}
